package com.hyj.serve.manage.service;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.hyj.serve.manage.configure.exception.ServiceException;
import com.hyj.serve.manage.entity.firewall.*;
import com.hyj.serve.manage.entity.HostEntity;
import com.hyj.serve.manage.utils.SSHClient;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author HeYuJie
 * @date 2022/6/2
 */
@Service
public class FirewallService extends HostServiceWidget {

    /**
     * 获取防火墙信息
     * @return
     */
    public FirewallInfo getInfo(){

        FirewallInfo info = new FirewallInfo();

        SSHClient sshClient = SSHClient();
        String result = sshClient.exec("firewall-cmd --state").trim();
        info.setState(result.equals("running"));

        FirewallZone firewallZone = getZoneInfo();
        if(firewallZone != null){
            info.setRules(firewallZone.getRules());
        }

        return info;

    }

    public FirewallZone getZoneInfo(){
        SSHClient sshClient = SSHClient();
        String xml = sshClient.exec("cat /etc/firewalld/zones/public.xml");
        return FirewallZone.deserializeXml(xml.trim());

    }

    /**
     * 修改防火墙状态
     * @param state 是否开启
     */
    public boolean state(boolean state) {
        SSHClient sshClient = SSHClient();
        if(state){
            sshClient.exec("systemctl start firewalld.service");
        } else {
            sshClient.exec("systemctl stop firewalld.service");
        }
        return true;
    }

    /**
     * 获取服务列表
     */
    public String[] services() {
        SSHClient sshClient = SSHClient();
        String exec = sshClient.exec("ls /usr/lib/firewalld/services");
        if(StrUtil.isEmpty(exec)){
            return new String[0];
        }
        String[] services = exec.split("\n");
        for (int i=0, len=services.length; i<len; i++) {
            String service = services[i];
            services[i] = service.substring(0, service.length() - 4);
        }

        return services;
    }

    /**
     * 更新防火墙规则
     */
    public void updateRule(JSONArray jsonArray) {
        if(jsonArray == null){
            return;
        }

        List<RuleItem> rules = new ArrayList<>(jsonArray.size());
        for (int i = 0, len=jsonArray.size(); i < len; i++) {
            JSONObject json = jsonArray.getJSONObject(i);
            String type = json.getString("type");
            if(FirewallRule.TAG_NAME.equals(type)){
                FirewallRule firewallRule = json.toJavaObject(FirewallRule.class);
                rules.add(firewallRule);

            } else if(PortRule.TAG_NAME.equals(type)){
                PortRule firewallRule = json.toJavaObject(PortRule.class);
                rules.add(firewallRule);

            } else if(SourceRule.TAG_NAME.equals(type)){
                SourceRule firewallRule = json.toJavaObject(SourceRule.class);
                rules.add(firewallRule);

            } else if(ServiceRule.TAG_NAME.equals(type)){
                ServiceRule firewallRule = json.toJavaObject(ServiceRule.class);
                rules.add(firewallRule);
            }
        }

        // 查询防火墙配置
        FirewallZone zone = getZoneInfo();
        zone.setRules(rules);

        save(zone);
    }

    /**
     * 保存防火墙配置
     */
    private void save(FirewallZone zone) {
        String xml = zone.serializeXml("");
        // 先备份文件
        SSHClient sshClient = SSHClient();
        String backupFile = DateUtil.format(new Date(), "yyyyMMddHHmmssSSS");
        sshClient.exec("mkdir /etc/firewalld/zones/backups & mv /etc/firewalld/zones/public.xml /etc/firewalld/zones/backups/"+ backupFile +".xml");
        sshClient.write("/etc/firewalld/zones/public.xml", xml);

        String exec = sshClient.exec("firewall-cmd --check-config").trim();
        if("success".equals(exec)){
            sshClient.exec("firewall-cmd --reload");
        } else {
            // 撤回
            sshClient.exec("rm -fr /etc/firewalld/zones/public.xml & mv /etc/firewalld/zones/backups/"+ backupFile +".xml /etc/firewalld/zones/public.xml");
            throw new ServiceException("更新防火墙规则失败==> ", exec);
        }
    }
}
